package com.rtf.framework.monitor.export;

import com.rtf.framework.monitor.AppMonitorExporter;
import com.rtf.framework.monitor.config.AppMonitorProperties;
import com.rtf.framework.monitor.support.AppMonitorNameConverter;
import com.google.common.collect.Lists;
import com.netflix.client.ClientFactory;
import com.netflix.loadbalancer.AbstractLoadBalancer;
import com.netflix.loadbalancer.LoadBalancerStats;
import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ServerStats;
import io.prometheus.client.Collector;
import io.prometheus.client.CollectorRegistry;
import io.prometheus.client.GaugeMetricFamily;
import lombok.Setter;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * ribbion负载均衡指标监控导出
 * @Author : liupeng
 * @Date : 2020-02-01
 * @Modified By
 */
public class AppRibbonExport extends Collector implements AppMonitorExporter {

    @Setter
    private static Set<String> clientNames ;

    @Setter
    private static AppMonitorNameConverter clientNameConverter = new AppMonitorNameConverter.Default() ;

    @Override
    public String getName() {
        return "ribbon";
    }

    @Override
    public synchronized void export(CollectorRegistry collectorRegistry) {
        new AppRibbonExport().register( collectorRegistry ) ;
    }

    @Override
    public List<MetricFamilySamples> collect() {
        List<MetricFamilySamples> mfs = Lists.newArrayList( ) ;
        // 获取本机上调用的client信息
        if( clientNames==null || clientNames.size()<1 ){
            return mfs ;
        }

        for (String clientName : clientNames) {
            // 标签属性
            List<String> labels = Arrays.asList("clientName" , "host" , "appName") ;

            String convertedClientName = clientNameConverter.convert( clientName ) ;

            // 不同服务器并发请求的数量
            GaugeMetricFamily activeRequestsCountGauge = new GaugeMetricFamily("ribbon_activerequestscount",
                    "并发请求数量", labels ) ;
            // 总请求数量
            GaugeMetricFamily totalRequestsCountGauge = new GaugeMetricFamily("ribbon_totalrequestscount",
                    "总请求数量", labels ) ;
            // 平均响应时间
            GaugeMetricFamily responseTimeAvgGauge = new GaugeMetricFamily("ribbon_responsetimeavg",
                    "平均响应时间(ms)", labels ) ;

            // 最大响应时间
            GaugeMetricFamily responseTimeMaxGauge = new GaugeMetricFamily("ribbon_responsetimemax",
                    "最大响应时间(ms)", labels ) ;

            // 最小响应时间
            GaugeMetricFamily responseTimeMinGauge = new GaugeMetricFamily("ribbon_responsetimemin",
                    "最小响应时间(ms)", labels ) ;

            // 是否熔断
            GaugeMetricFamily circuitBreakerTrippedGauge = new GaugeMetricFamily("ribbon_circuitbreakertripped",
                    "是否熔断", labels ) ;

            // 获取负载均衡器
            AbstractLoadBalancer loadBalancer = (AbstractLoadBalancer) ClientFactory.getNamedLoadBalancer(clientName) ;
            // 获取所有节点的统计信息
            LoadBalancerStats loadBalancerStats = loadBalancer.getLoadBalancerStats() ;
            Map<Server, ServerStats> serverServerStats = loadBalancerStats.getServerStats() ;
            // 构建所有节点的统计
            for (Map.Entry<Server, ServerStats> entry : serverServerStats.entrySet()) {
                Server server = entry.getKey() ;
                ServerStats serverStats = entry.getValue() ;

                // 构建标签值，必须与labels对应
                List<String> labelValues = Arrays.asList( convertedClientName , server.getHostPort() , AppMonitorProperties.getAppName() ) ;

                activeRequestsCountGauge.addMetric( labelValues , serverStats.getActiveRequestsCount() ) ;

                totalRequestsCountGauge.addMetric( labelValues , serverStats.getTotalRequestsCount() ) ;

                responseTimeAvgGauge.addMetric( labelValues , serverStats.getResponseTimeAvg() ) ;

                responseTimeMaxGauge.addMetric( labelValues , serverStats.getResponseTimeMax() ) ;

                responseTimeMinGauge.addMetric( labelValues , serverStats.getResponseTimeMin() ) ;

                circuitBreakerTrippedGauge.addMetric( labelValues , serverStats.isCircuitBreakerTripped() ? 1 : 0 ) ;
            }

            mfs.addAll( Lists.newArrayList( activeRequestsCountGauge ,totalRequestsCountGauge ,
                    responseTimeAvgGauge , responseTimeMaxGauge ,responseTimeMinGauge ,
                    circuitBreakerTrippedGauge  ) ) ;
        }

        return mfs ;
    }
}
